<?php

session_set_save_handler ( array (
		'SessionManager',
		'open' 
), array (
		'SessionManager',
		'close' 
), array (
		'SessionManager',
		'read' 
), array (
		'SessionManager',
		'write' 
), array (
		'SessionManager',
		'destroy' 
), array (
		'SessionManager',
		'gc' 
) );
class SessionManager {
	/**
	 * <h2>实例对象</h2>
	 * <p>会话管理器采用单件模式</p>
	 *
	 * @var SessionManager
	 */
	private static $_instance = null;
	
	/**
	 * <h2>日志对象</h2>
	 *
	 * @var Logger
	 */
	private static $_logger;
	
	/*
	 * <h2>指示会话是否开启</h2>
	 */
	private $_started = false;
	/**
	 * <h2>私有化的构造函数，保证对象不能被直接实例化</h2>
	 * <p>构造函数中初始化日志对象</p>
	 */
	private function __construct() {
		Logger::configure ( ROOT_PATH . 'config/log_config.xml' );
		self::$_logger = Logger::getLogger ( __CLASS__ );
	}
	
	/**
	 * <h2>析构函数</h2>
	 * <p>将session写入持久化存储，并结束session</p>
	 */
	public function __destruct() {
		session_write_close ();
	}
	
	/**
	 * <h2>getSingleton</h2>
	 * <p>获取SessionManager的单件实例，SessionManager必须透过此方法获取实例</p>
	 *
	 * @return SessionManager
	 */
	public static function getSingleton() {
		if (empty ( self::$_instance )) {
			self::$_instance = new SessionManager ();
		}
		return self::$_instance;
	}
	
	/**
	 * <h2>获取会话属性</h2>
	 *
	 * @param string $name
	 *        	属性名字
	 */
	public function getAttribute($name) {
		return isset ( $_SESSION [$name] ) ? $_SESSION [$name] : null;
	}
	
	/**
	 * <h2>获取属性</h2>
	 *
	 * @param string $name
	 *        	属性名字
	 * @param mixed $value
	 *        	属性值
	 */
	public function setAttribute($name, $value) {
		$_SESSION [$name] = $value;
	}
	
	/**
	 * <h2>删除一个会话属性</h2>
	 *
	 * @param string $name        	
	 */
	public function delAttribute($name) {
		if (isset ( $_SESSION [$name] ))
			unset ( $_SESSION [$name] );
	}
	/**
	 * <h2>开始会话</h2>
	 *
	 * @return boolean
	 */
	public function startSession() {
		if (! $this->_started) {
			$this->_started = session_start ();
		}
		return $this->_started;
	}
	
	/**
	 * <h2>销毁会话</h2>
	 *
	 * @param bool $clearClient
	 *        	指示是否清理客户端
	 */
	public function destorySession($clearClient = true) {
		session_destroy ();
		session_unset ();
	}
	
	/**
	 * <h2>打开会话</h2>
	 *
	 * @param string $path        	
	 * @param string $name        	
	 * @return bool
	 */
	public static function open($path, $name) {
		return true;
	}
	
	/**
	 */
	public static function close() {
		return true;
	}
	
	/**
	 *
	 * @return string
	 */
	public static function read($sid) {
		$conn = DBHelper::getDB ();
		$query = "SELECT ts_lastaccess, session" . LB;
		$query .= " FROM sessions where sid=:sid LIMIT 1";
		$params = array (
				"sid" => $sid 
		);
		$map [] = array (
				"sid",
				"string" 
		);
		$table = $conn->select ( $query, $params, $map );
		if (count ( $table ) == 0) {
			return "";
		}
		$now = time ();
		$ts_lastaccess = $table [0] ["ts_lastaccess"];
		if ($now - $ts_lastaccess > SESSION_DEFAULT_LIFETIME) { // 强制过期
		                                                        // session_destroy
		                                                        // ();
		                                                        // session_unset
		                                                        // ();
			return "";
		}
		return $table [0] ["session"];
	}
	
	/**
	 * <h2>Session写入函数</h2>
	 *
	 * @param string $identifier        	
	 * @param string $value        	
	 */
	public static function write($sid, $value) {
		if (empty ( $sid ) || is_null ( $value )) {
			self::$_logger->error ( "session sid or value can not be empty or null" . __FILE__ . __LINE__ );
			return false;
		}
		$conn = DBHelper::getDB ();
		$query = "SELECT sid FROM sessions WHERE sid=:sid LIMIT 1";
		$params = array (
				"sid" => $sid 
		);
		$map = array (
				array (
						"sid",
						"string" 
				) 
		);
		$table = $conn->select ( $query, $params, $map );
		if (count ( $table ) > 0) {
			// do update
			$query = "UPDATE sessions SET ts_lastaccess=:ts_lastaccess, session=:session " . LB;
			$query .= "WHERE sid=:sid";
			$params = array (
					"ts_lastaccess" => time (),
					"session" => $value,
					"sid" => $sid 
			);
			// @formatter:off
			$map = array (
					array ("ts_lastaccess","int"),
					array (	"session","string"),
					array (	"sid","string")
					);
			// @formatter:on
			$conn->update ( $query, $params, $map );
		} else {
			// insert
			$query = "INSERT INTO sessions SET sid=:sid, ts_created=:ts_created,
			 ts_lastaccess=:ts_lastaccess, session=:session";
			$params = array (
					"sid" => $sid,
					"ts_created" => time (),
					"ts_lastaccess" => time (),
					"session" => $value 
			);
			// @formatter:off
			$map = array (
					array ("sid","string"),
					array ("ts_created","int"),
					array ("ts_lastaccess","int"),
					array ("session","string") 
			);
			// @formatter:on
			$conn->insert ( $query, $params, $map );
		}
		return true;
	}
	
	/**
	 *
	 * @param string $sid        	
	 */
	public static function destroy($sid) {
		if (! empty ( $sid )) {
			$conn = DBHelper::getDB ();
			$query = "DELETE FROM sessions where sid=:sid";
			$params = array (
					"sid" => $sid 
			);
			$map [] = array (
					"sid",
					"string" 
			);
			$conn->delete ( $query, $params, $map );
		}
		return true;
	}
	
	/**
	 * <h2>SESSION GC</h2>
	 * <p>删除过期回话</p>
	 *
	 * @param int $maxlifetime
	 *        	timestamp Ignore
	 */
	public static function gc($maxlifetime) {
		$conn = DBHelper::getDB ( false );
		if (defined ( "SESSION_DEFAULT_LIFETIME" )) {
			$maxlifetime = SESSION_DEFAULT_LIFETIME;
		}
		$expireTimestamp = time () - $maxlifetime;
		$query = "DELETE FROM sessions WHERE ts_lastaccess<{$expireTimestamp}";
		$table = $conn->delete ( $query );
		return true;
	}
}
